.section .os_hal.intvect, "ax"  @让GCC把下面指令放在一个叫 .os_hal.intvect 的节中，以便链接器处理
.code  32                       @让GCC生成32位的ARMCPU指令
.align 4                        @4字节对齐

.extern hal_undefined_distribute
.extern hal_swi_distribute
.extern hal_preincabort_distribute
.extern hal_dataabort_distribute
.extern hal_irq_distribute
.extern hal_frq_distribute

.global int_vectors_undefined
.global int_vectors_swi
.global int_vectors_preincabort
.global int_vectors_dataabort
.global int_vectors_bugdie
.global int_vectors_irq
.global int_vectors_frq

.equ ALLREGS_STKSZ, 64
.equ STKOFFSET_PC, 60
.equ NPCREGS_STKSZ, 60
 
.equ CPUMODE_MASK, 31
.equ CPUSVE_MODE, 19
.equ MSTK_OFF, 12
.equ NINT_SVEMODE, 0xd3
.equ NINT_IRQMODE, 0xd2
.equ NINT_FRQMODE, 0xd1
.equ NINT_ABTMODE, 0xd7
.equ NINT_UNDMODE, 0xdb

@ 代码功能分4部分：
@ 1) 保存用户模式下的 R0 ~ R14 寄存器
@ 2) 切换CPU模式并保存发生异常前的 PC 和 CPSR 寄存器
@ 3) 调用一个 C函数
@ 4) 恢复先前保存的那些寄存器以达到异常处理的返回

int_vectors_undefined:

        @ 1) 保存用户模式下的 R0 ~ R14 寄存器

        msr   cpsr_c, #NINT_SVEMODE     @ 切换至特管理权模式并关中断 (_c后缀只改变CPSR寄存器第8位)
        sub   sp, sp, #ALLREGS_STKSZ    @ 把特权管理模式下的 SP (内核栈寄存器) 减去 64字节
        stmia sp, {r0-lr}^              @ 对于 stmia 指令 有^后缀表示操作的是用户模式的 R0 ~ R14 这15个寄存器

        @ 2) 切换CPU模式并保存发生异常前的 PC 和 CPSR 寄存器

        msr   cpsr_c, #NINT_UNDMODE     @ 切换至未定义指令异常模式
        sub   r1, lr, #0                @ 把未定义指令模式的 LR 寄存器读到 R1 中 (即异常发生时的 PC)
        mrs   r0, spsr                  @ 把未定义指令异常模式的 SPSR 放进 R0 中 (即异常发生时的 CPSR)
        msr   cpsr_c, #NINT_SVEMODE     @ 切回特权管理模式
        str   r1, [sp, #STKOFFSET_PC]   @ 把 R1 写入 sp + STKOFFSET_PC 地址的内核栈中
        stmfd sp!, {r0, lr}             @ 把以前的 (指令异常模式) CPSR 和 特权模式的 LR 压栈, 并更新 SP 内核栈指针

        @ 3) 调用一个 C函数 

        mov   r0, sp                    @ 把当前 SP 写进 R0, 相当于给 C函数 传递一个参数
        bl    hal_undefined_distribute  @ 调用 C函数 把返回地址写入 LR 中 (上面代码已把 未定义指令模式 的 LR 压入栈中)

        @ 4) 恢复先前保存的那些寄存器以达到异常处理的返回

        ldmfd sp!, {r0,lr}              @ 从内核栈中 弹出 两个字 到 R0, LR 中 (R0 就是 先前 压入的 用户模式 的 CPSR)
        msr   spsr, r0                  @ 把 用户模式 的 CPSR 放入当前 CPU工作模式下的 CPSR
        ldmia sp, {r0-lr}^              @ 从 SP 指向的内核栈中 加载 15个字 到用户模式的 R0 ~ R14 寄存器中
        add   sp, sp, #NPCREGS_STKSZ    @ 把内核栈指针加上 60字节, 使之指向前 PC 存放的地址
        ldmfd sp!, {pc}^                @ 从内核栈中 弹出 1个字 到 用户 PC中, 同时将 SPCR 复制到 CPSR 中, 并且同时更细内核栈 SP 使之平衡
                                        @ 因为更新了 CPSR 所以会导致CPU切换回发生异常前的工作模式 (实现了异常处理后的返回)

int_vectors_swi:
        sub   sp, sp, #ALLREGS_STKSZ    @ 把特权管理模式下的 SP (内核栈寄存器) 减去 64字节
        stmia sp, {r1-lr}^              @ 对于 stmia 指令 有^后缀表示操作的是用户模式的 R0 ~ R14 这15个寄存器
        mrs   r1, spsr                  @ 把 SPSR (前 CPSR)  放进 R1 中 
        str   lr, [sp, #STKOFFSET_PC]   @ 把 LR (前 PC) 写入 sp + STKOFFSET_PC 地址的内核栈中
        stmfd sp!, {r1, lr}
        mov   r1, sp
        bl    hal_swi_distribute        @ 调用 C函数
        ldmfd sp!, {r1, lr}             @ 从内核栈中 弹出 两个字 到 R1, LR 中
        msr   spsr, r1
        ldmia sp, {r1-lr}^              @ 从 SP 指向的内核栈中 加载 15个字 到用户模式的 R0 ~ R14 寄存器中
        add   sp, sp, #NPCREGS_STKSZ    @ 把内核栈指针加上 60字节, 使之指向前 PC 存放的地址
        ldmfd sp!, {pc}^                @ 从内核栈中 弹出 1个字 到 用户 PC中, 同时将 SPCR 复制到 CPSR 中, 并且同时更细内核栈 SP 使之平衡
                                        @ 因为更新了 CPSR 所以会导致CPU切换回发生异常前的工作模式 (实现了异常处理后的返回)

int_vectors_preincabort:
        msr   cpsr_c, #NINT_SVEMODE
        sub   sp, sp, #ALLREGS_STKSZ
        stmia sp, {r0-lr}^
        msr   cpsr_c, #NINT_ABTMODE
        sub   r1, lr, #4
        mrs   r0, spsr
        msr   cpsr_c, #NINT_SVEMODE
        str   r1, [sp, #STKOFFSET_PC]
        stmfd sp!, {r0, lr}
        mov   r0, sp
        bl    hal_preincabort_distribute
        ldmfd sp!, {r0, lr}
        msr   spsr, r0
        ldmia sp, {r0-lr}^
        add   sp, sp, #NPCREGS_STKSZ
        ldmfd sp!, {pc}^

int_vectors_dataabort:
	    msr   cpsr_c, #NINT_SVEMODE
        sub   sp, sp, #ALLREGS_STKSZ
        stmia sp, {r0-lr}^
        msr   cpsr_c, #NINT_ABTMODE
        sub   r1, lr, #8
        mrs   r0, spsr
        msr   cpsr_c, #NINT_SVEMODE
        str   r1, [sp, #STKOFFSET_PC]
        stmfd sp!, {r0, lr}
        mov   r0, sp
        bl    hal_dataabort_distribute
        ldmfd sp!, {r0, lr}
        msr   spsr, r0
        ldmia sp, {r0-lr}^
        add   sp, sp, #NPCREGS_STKSZ
        ldmfd sp!, {pc}^

int_vectors_bugdie:
        b .     @死循环

int_vectors_irq:

        @ 1) 保存用户模式下的 R0 ~ R14 寄存器

        msr   cpsr_c, #NINT_SVEMODE         @ 切换至特权管理模式并关中断 (_c后缀只改变CPSR寄存器第8位)
        sub   sp, sp, #ALLREGS_STKSZ        @ 把特权管理模式下的 SP (内核栈寄存器) 减去 64字节
        stmia sp, {r0-lr}^                  @ 对于 stmia 指令 有^后缀表示操作的是用户模式的 R0 ~ R14 这15个寄存器

        @ 2) 切换CPU模式并保存发生异常前的 PC 和 CPSR 寄存器        

        msr   cpsr_c, #NINT_IRQMODE         @ 切换至中断模式并关中断 (_c后缀只改变CPSR寄存器第8位)
        sub   r1, lr, #4                    @ 把中断模式的 LR 寄存器读到 R1 中 (即中断发生时的 PC) (因为处理器流水线, 所以前PC减4才是正确的返回地址)
        mrs   r0, spsr                      @ 把中断模式的 SPSR 放进 R0 中
        msr   cpsr_c, #NINT_SVEMODE         @ 切回特权管理模式
        str   r1, [sp, #STKOFFSET_PC]       @ 把 R1 写入 sp + STKOFFSET_PC 地址的内核栈中
        stmfd sp!, {r0, lr}                 @ 把以前的 (中断模式) CPSR 和 特权管理模式的 LR 压栈, 并更新 SP 内核栈指针

        @ 3) 调用一个 C函数 

        mov   r0, sp                        @ 把当前 SP 写进 R0, 相当于给 C函数 传递一个参数
        bl    hal_irq_distribute            @ 调用 C函数 把返回地址写入 LR 中 (上面代码已把 中断模式 的 LR 压入栈中)

        @ 4) 恢复先前保存的那些寄存器以达到异常处理的返回

        ldmfd sp!, {r0, lr}                 @ 从内核栈中 弹出 两个字 到 R0, LR 中 (R0 就是 先前 压入的 用户模式 的 CPSR)
        msr   spsr, r0                      @ 把 用户模式 的 CPSR 放入当前 CPU工作模式下的 CPSR
        ldmia sp, {r0-lr}^                  @ 从 SP 指向的内核栈中 加载 15个字 到用户模式的 R0 ~ R14 寄存器中
        add   sp, sp, #NPCREGS_STKSZ        @ 把内核栈指针加上 60字节, 使之指向前 PC 存放的地址
        ldmfd sp!, {pc}^                    @ 从内核栈中 弹出 1个字 到 用户 PC中, 同时将 SPCR 复制到 CPSR 中, 并且同时更细内核栈 SP 使之平衡
                                            @ 因为更新了 CPSR 所以会导致CPU切换回发生异常前的工作模式 (实现了异常处理后的返回)

int_vectors_frq:
        msr   cpsr_c, #NINT_SVEMODE
        sub   sp, sp, #ALLREGS_STKSZ
        stmia sp, {r0-lr}^
        msr   cpsr_c, #NINT_FRQMODE
        sub   r1, lr, #4
        mrs   r0, spsr
        msr   cpsr_c, #NINT_SVEMODE
        str   r1, [sp, #STKOFFSET_PC]
        stmfd sp!, {r0, lr}
        mov   r0, sp
        bl    hal_frq_distribute
        ldmfd sp!, {r0, lr}
        msr   spsr, r0
        ldmia sp, {r0-lr}^
        add   sp, sp, #NPCREGS_STKSZ
        ldmfd sp!, {pc}^

.end
